/**
 * 
 */
package com.workable.assignment.client;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.sun.jersey.api.client.ClientResponse;
import com.workable.assignment.Constants;
import com.workable.assignment.annotations.CacheRTMovieReviews;
import com.workable.assignment.annotations.CacheRTMovies;
import com.workable.assignment.annotations.CacheRTMoviesInTheater;
import com.workable.assignment.annotations.CacheTMDBMovieDetails;
import com.workable.assignment.annotations.CacheTMDBMovieReviews;
import com.workable.assignment.annotations.CacheTMDBMovies;
import com.workable.assignment.annotations.CacheTMDBMoviesInTheater;
import com.workable.assignment.cache.MovieRamaCacheManager;
import com.workable.assignment.domain.rottentomatoes.RTMovie;
import com.workable.assignment.domain.rottentomatoes.RTMovieReviews;
import com.workable.assignment.domain.rottentomatoes.RTMovieSearchResult;
import com.workable.assignment.domain.themoviedb.TMDBMovie;
import com.workable.assignment.domain.themoviedb.TMDBMovieDetails;
import com.workable.assignment.domain.themoviedb.TMDBMovieReviews;
import com.workable.assignment.domain.themoviedb.TMDBMovieSearchResult;

/**
 * @author npapadopoulos
 * @date Oct 23, 2014
 * 
 */
@Component
public class MovieRamaClient extends AbstractMovieRamaClient {

    private static final Logger LOG = (Logger) LoggerFactory.getLogger(MovieRamaClient.class);

    @Autowired
    private String RTApiKey;

    @Autowired
    private String RTURL;

    @Autowired
    private String TMDBApiKey;

    @Autowired
    private String TMDBURL;

    @Autowired
    private MovieRamaCacheManager movieRamaCacheManager;

    @Override
    @CacheRTMoviesInTheater
    public List<RTMovie> getRTMoviesInTheater() {
        ClientResponse response = call(RTURL + Constants.ROTTEN_TOMATOES_SEARCH_MOVIES_IN_THEATERS_PATH + "?apikey="
            + RTApiKey);
        RTMovieSearchResult movieSearchResult = null;
        try {
            movieSearchResult = getObjectMapper().readValue(response.getEntityInputStream(), RTMovieSearchResult.class);
            movieRamaCacheManager.addMoviesCache(movieSearchResult.getMovies(), Constants.CACHE_RT_MOVIES_NAME);
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found " + movieSearchResult.getMovies().size() + " movies in Rotten Tomatoes Database.");
        }
        return movieSearchResult != null ? movieSearchResult.getMovies() : null;
    }

    @Override
    @CacheRTMovies
    public List<RTMovie> getSearchedRTMovies(String query) throws UnsupportedEncodingException {
        List<RTMovie> rtm = movieRamaCacheManager.loadRTMoviesFromCache(query);
        if (rtm != null) {
            return rtm;
        }

        ClientResponse response = call(RTURL + Constants.ROTTEN_TOMATOES_SEARCH_MOVIES_PATH + "?apikey=" + RTApiKey
            + "&q=" + URLEncoder.encode(query.toLowerCase().trim(), "UTF-8"));
        RTMovieSearchResult movieSearchResult = null;
        try {
            movieSearchResult = getObjectMapper().readValue(response.getEntityInputStream(), RTMovieSearchResult.class);
            movieRamaCacheManager.addMoviesCache(movieSearchResult.getMovies(), Constants.CACHE_RT_MOVIES_NAME);
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found " + movieSearchResult.getMovies().size() + " movies in Rotten Tomatoes Database.");
        }

        return movieSearchResult != null ? movieSearchResult.getMovies() : null;
    }

    @Override
    @CacheTMDBMovieReviews
    public RTMovieReviews getRTMovieReviews(long id) {
        Future<ClientResponse> future = callAsync(RTURL + Constants.ROTTEN_TOMATOES_MOVIE_PATH + "/" + id
            + "/reviews.json?apikey=" + RTApiKey);
        RTMovieReviews rtMovieReviews = null;
        try {
            rtMovieReviews = getObjectMapper().readValue(future.get().getEntityInputStream(), RTMovieReviews.class);
        } catch (IOException | InterruptedException | ExecutionException e) {
            LOG.error(e.getMessage(), e);
        }
        return rtMovieReviews;
    }

    @Override
    @CacheTMDBMoviesInTheater
    public List<TMDBMovie> getTMDBMoviesInTheater() {
        ClientResponse response = call(TMDBURL + Constants.THE_MOVIEDB_SEARCH_IN_THEATERS_MOVIES_PATH + "?api_key="
            + TMDBApiKey);
        TMDBMovieSearchResult movieSearchResult = null;
        try {
            movieSearchResult = getObjectMapper().readValue(response.getEntityInputStream(),
                TMDBMovieSearchResult.class);
            movieRamaCacheManager.addMoviesCache(movieSearchResult.getResults(), Constants.CACHE_TMDB_MOVIES_NAME);
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found " + movieSearchResult.getResults().size() + " movies in TheMovieDB Database.");
        }
        return movieSearchResult != null ? movieSearchResult.getResults() : null;
    }

    @Override
    @CacheTMDBMovies
    public List<TMDBMovie> getSearchedTMDBMovies(String query) throws UnsupportedEncodingException {
        List<TMDBMovie> rtm = movieRamaCacheManager.loadTMDBMoviesFromCache(query);
        if (rtm != null) {
            return rtm;
        }

        ClientResponse response = call(TMDBURL + Constants.THE_MOVIEDB_SEARCH_MOVIES_PATH + "?api_key=" + TMDBApiKey
            + "&query=" + URLEncoder.encode(query.toLowerCase().trim(), "UTF-8"));
        TMDBMovieSearchResult movieSearchResult = null;
        try {
            movieSearchResult = getObjectMapper().readValue(response.getEntityInputStream(),
                TMDBMovieSearchResult.class);
            movieRamaCacheManager.addMoviesCache(movieSearchResult.getResults(), Constants.CACHE_TMDB_MOVIES_NAME);
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("Found " + movieSearchResult.getResults().size() + " movies in TheMovieDB Database.");
        }
        return movieSearchResult != null ? movieSearchResult.getResults() : null;
    }

    @Override
    @CacheTMDBMovieDetails
    public TMDBMovieDetails getTMDBMovieDetails(long id) {
        Future<ClientResponse> future = callAsync(TMDBURL + Constants.THE_MOVIEDB_MOVIE_PATH + "/" + id + "?api_key="
            + TMDBApiKey);
        TMDBMovieDetails tmdbMovieDetails = null;
        try {
            tmdbMovieDetails = getObjectMapper().readValue(future.get().getEntityInputStream(), TMDBMovieDetails.class);
        } catch (IOException | InterruptedException | ExecutionException e) {
            LOG.error(e.getMessage(), e);
        }
        return tmdbMovieDetails;
    }

    @Override
    @CacheRTMovieReviews
    public TMDBMovieReviews getTMDBMovieReviews(long id) {
        Future<ClientResponse> future = callAsync(TMDBURL + Constants.THE_MOVIEDB_MOVIE_PATH + "/" + id
            + "/reviews?api_key=" + TMDBApiKey);
        TMDBMovieReviews tmdbMovieReviews = null;
        try {
            tmdbMovieReviews = getObjectMapper().readValue(future.get().getEntityInputStream(), TMDBMovieReviews.class);
        } catch (IOException | InterruptedException | ExecutionException e) {
            LOG.error(e.getMessage(), e);
        }
        return tmdbMovieReviews;
    }
}
